#!/bin/env wowlua

if arg[0] == "get-talent-id.lua" then
	dofile("config.lua")
end

local DEBUG = DEBUG or 1

local function dprint(dlevel, ...)
	if dlevel and DEBUG >= dlevel then
		print(...)
	end
end

local url = require("socket.url")
local httptime, httpcount = 0, 0
local getpage
do
	local status, curl = pcall(require, "curl")
	if status then
		local temp
		local write = function (s, len)
			temp[#temp + 1] = s
			return len
		end
		local c = curl.easy_init()
		function getpage(url)
			dprint(2, "curl", url)
			temp = {}
			c:setopt(curl.OPT_URL, url)
			c:setopt(curl.OPT_WRITEFUNCTION, write)
			local stime = os.time()
			local err, info = c:perform()
			httptime = httptime + (os.time() - stime)
			httpcount = httpcount + 1
			if err ~= 0 then
				dprint(1, "curl error", url, info)
			else
				temp = table.concat(temp)
				if temp:len() > 0 then
					return temp
				end
			end
		end
	else
		local http = require("socket.http")

		function getpage(url)
			dprint(2, "socket.http", url)
			local stime = os.time()
			local r = http.request(url)
			httptime = httptime + (os.time() - stime)
			httpcount = httpcount + 1
			return r
		end
	end
end

if not NOCACHE then
	local real_getpage = getpage
	local status, sqlite = pcall(require, "lsqlite3")
	if status then
		db = sqlite.open("wowhead.db")
		db:exec([[
CREATE TABLE IF NOT EXISTS cache (
	url TEXT,
	content BLOB,
	time TEXT,
	PRIMARY KEY (url)
)]])
		local CACHE_TIMEOUT = CACHE_TIMEOUT or "+7 day"
		local select_stmt = db:prepare("SELECT content FROM cache WHERE url = ? AND datetime(time, '"..CACHE_TIMEOUT.."') > datetime('now')")
		local insert_stmt = db:prepare("INSERT INTO cache VALUES (?, ?, CURRENT_TIMESTAMP)")
		getpage = function (url)
			select_stmt:bind_values(url)
			local result = select_stmt:step()
			if result == sqlite3.ROW then
				result = select_stmt:get_value(0)
				select_stmt:reset()
				return result
			else
				select_stmt:reset()
			end
			local content = real_getpage(url)
			if content then
				insert_stmt:bind_values(url, content)
				insert_stmt:step()
				insert_stmt:reset()
			end
			return content
		end
	else
		local page_cache = {}
		getpage = function (url)
			local page = page_cache[url]
			if not page then
				page = real_getpage(url)
				page_cache[url] = page
			end
			return page
		end
	end
end

local function load(url)
	local page = getpage(url)
	local result = {}
	for view in page:gmatch("new Listview(%b())") do
		local name = view:match("id: '([^']+)'")
		if name == 'spells' then
			local spelllist = view:match("data%: (%b[])")
			for spellstring in spelllist:gmatch("%b{}") do
				local id = spellstring:match("{id:(%d+)")
				local name = spellstring:match("name:'@([^,]+)'"):replace("\\'", "'")
				local rank = spellstring:match("rank:'Rank (%d+)'")
				result[#result + 1] = { id = tonumber(id), name = name, rank = tonumber(rank) or 1 }
			end
		end
		if not names then break end
	end
	return result
end

local function find_index(list, row, column)
	for index, data in ipairs(list) do
		if data.info.row == row and data.info.column == column then
			return index
		end
	end
end

local function resolve_dependies(data)
	for _, classinfo in pairs(data) do
		for _, tabinfo in pairs(classinfo) do
			for _, talent in ipairs(tabinfo.talents) do
				local info = talent.info
				if info.prereqs then
					info.dep = find_index(tabinfo.talents, info.prereqs.row, info.prereqs.column)
				end
			end
		end
	end
end

local function load_talented_data()
	function GetLocale() return "enUS" end
	dofile(OUTPUT.."Talented_Data_init.lua")
	for class in pairs(CLASSES) do
		dofile(OUTPUT.."Talented_Data_"..class..".lua")
	end
	dofile(OUTPUT.."Talented_Data_enUS.lua")
	local data = Talented_Data
	Talented_Data = nil
	GetLocale = nil
	return data
end

local Name_Conversion = {
	["Incinerate"] = "Incineration",
	["Improved Fire Nova Totem"] = "Improved Fire Totems",
	["Improved Fire Ward"] = "Molten Shields",
	["Improved Backstab"] = "Puncturing Wounds",
}

local function find_spell_id(s, name, rank)
	name = Name_Conversion[name] or name
	for _, v in pairs(s) do
		if v.name == name and v.rank == rank then
			return v.id
		end
	end
	error(("%s (%d) not found"):format(name, rank))
end

local function main()
	local data = load_talented_data()
	for class, id in pairs(CLASSES) do
		local s = load(WOWHEAD_BASE..id)
		
		local cinfo = data[class]
		for tab, talents in ipairs(cinfo) do
			for index, talent in ipairs(talents.talents) do
				local info = talent.info
				local name = info.name
				local ids = {}
				for i = 1, info.ranks do
					ids[i] = find_spell_id(s, name, i)
				end
				info.ids = ids
			end
		end
	end
	
	print("Outputing to "..TALENTED_PATH)
	local o = io.open(TALENTED_PATH.."spelldata.lua", "w")
	local out = function(s, ...)
		if s:find("%", nil, true) then
			s = s:format(...)
		end
		o:write(s.."\n")
	end
	out("-- Generated Data, do not modify")
	out("Talented.spelldata = {")
	for class in pairs(CLASSES) do
		local tabs = {}
		for tab, talents in ipairs(data[class]) do
			local stalents = {}
			for index, talent in ipairs(talents.talents) do
				local ranks = {}
				for i, id in ipairs(talent.info.ids) do
					ranks[i] = tostring(id)
				end
				stalents[index] = table.concat(ranks, ";")
			end
			tabs[tab] = table.concat(stalents, ",")
		end
		out("\t%s = %q,", class, table.concat(tabs, "|"))
	end
	out("}")
	o:close()
end

if arg[0] == "get-talent-id.lua" then
	main()
end
